package lab3.systemB;

import java.io.*;

public class SystemMain {

	/**
	 * Creaza componentele si porneste sistemul. Sunt asteptati doi parametrii
	 * de intrare: primul: numele fisierului de intrare ce contine
	 * inregistrarile corespunzatoare studentilor candidati, al doilea: numele
	 * fisierului de iesire ca va contine inregistrarile studentilor acceptati.
	 * 
	 * @param args
	 *            array cu parametrii de intrare
	 */
	public static void main(String[] args) {
		// Verificarea numarului parametrilor de intrare.
		if (args.length != 2) {
			System.out.println("Numar incorect de parametri");
			System.out
					.println("Utilizare corecta: java SystemMain <fisier_de_intrare> <fisier_de_iesire>");
			System.exit(1);
		}

		// Verificarea existentei fisierului de intrare.
		if (!new File(args[0]).exists()) {
			System.out.println("Could not find " + args[0]);
			System.exit(1);
		}

		// Vertificarea existentei directorului parinte al fisierului de iesire.
		// Crearea acestuia daca e necesar.
		File parentFile = new File(args[1]).getAbsoluteFile().getParentFile();
		if (!parentFile.exists() && !parentFile.mkdir()) {
			System.out.println("Nu s-a putut crea directorul parinte "
					+ args[1]);
			System.exit(1);
		}

		try {
			// _____________________________________________________________________
			// Crearea si legarea componentelor si conectorilor
			// _____________________________________________________________________

			// Crearea conductelor (de fapt, a rolurilor).
			System.out.println("Controller: Creare conectori (roluri)...");
			PipedWriter objTemp;

			BufferedWriter IACDSource = new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader IACDSync = new BufferedReader(new PipedReader(
					objTemp));
			
			BufferedWriter IACD_13456_Source = new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader IACD_13456_Sync = new BufferedReader(new PipedReader(
					objTemp));
			
			BufferedWriter IACD_No13456_Source = new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader IACD_No13456_Sync = new BufferedReader(new PipedReader(
					objTemp));
			
			BufferedWriter IACD_12333_Source= new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader IACD_12333_Sync = new BufferedReader(new PipedReader(
					objTemp));
			
			BufferedWriter IACD_merge_Source= new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader IACD_merge_Sync = new BufferedReader(new PipedReader(
					objTemp));
			
			
			
			
			BufferedWriter NonIACDSource = new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader NonIACDSync = new BufferedReader(new PipedReader(
					objTemp));
			
			BufferedWriter NonIACD_13456_Source = new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader NonIACD_13456_Sync = new BufferedReader(new PipedReader(
					objTemp));
			
			BufferedWriter NonIACD_No13456_Source = new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader NonIACD_No13456_Sync = new BufferedReader(new PipedReader(
					objTemp));
			
			BufferedWriter NonIACD_12333_Source = new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader NonIACD_12333_Sync = new BufferedReader(new PipedReader(
					objTemp));

			BufferedWriter NonIACD_merge_Source= new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader NonIACD_merge_Sync = new BufferedReader(new PipedReader(
					objTemp));
			
			BufferedWriter NonIACD_13222_Source = new BufferedWriter(
					objTemp = new PipedWriter());
			BufferedReader NonIACD_13222_Sync = new BufferedReader(new PipedReader(
					objTemp));
			
			
			
			BufferedReader inputFileSync = new BufferedReader(
					new FileReader(args[0]));
			BufferedWriter outputFileSource = new BufferedWriter(
					new FileWriter(args[1]));

			
			// Crearea filtrelor (transferul rolurilor ca parametrii, pentru a
			// fi legati
			// la porturile fiecarui filtru).
			System.out.println("Controller: Creare componente ...");

			SplitFilter filterSplitIACD = new SplitFilter("IACD",
					inputFileSync, IACDSource, NonIACDSource, "IACD");
		
			CourseFilter iacd13456 = new CourseFilter("13456", IACDSync,
					IACD_13456_Source, IACD_No13456_Source, 13456);
			CourseFilter iacd12333 = new CourseFilter("12333", IACD_No13456_Sync,
					IACD_12333_Source, null, 12333);
			MergeFilter mergeIacd = new MergeFilter("Merge IACD",
					IACD_13456_Sync, IACD_12333_Sync,
					IACD_merge_Source);

			
			CourseFilter nonIacd13456 = new CourseFilter("13456", NonIACDSync,
					NonIACD_13456_Source, NonIACD_No13456_Source, 13456);
			CourseFilter nonIacd12333 = new CourseFilter("12333", NonIACD_No13456_Sync,
					NonIACD_12333_Source, null, 12333);
			MergeFilter mergeNonIacd = new MergeFilter("Merge Non IACD",
					NonIACD_13456_Sync, NonIACD_12333_Sync,
					NonIACD_merge_Source);
			CourseFilter nonIacd13222 = new CourseFilter("3222", NonIACD_merge_Sync,
					NonIACD_13222_Source, null, 3222);
			
			
			MergeFilter merge = new MergeFilter("Merge IACD with Non IACD",
					IACD_merge_Sync, NonIACD_13222_Sync,
					outputFileSource);
			
			// _____________________________________________________________________
			// Executarea sistemului
			// _____________________________________________________________________

			// Start all filters.
			System.out.println("Controller: Pornire filtre ...");
			filterSplitIACD.start();
			iacd13456.start();
			nonIacd13456.start();
			iacd12333.start();
			nonIacd12333.start();
			mergeIacd.start();
			mergeNonIacd.start();
			nonIacd13222.start();
			merge.start();

			// Asteapta pana la terminarea datelor de pe lanturile conductelor
			// si filtrelor.
			// Ordinea de verificare, de la intrare la iesire, este importanta
			// pentru a evita problemele de concurenta.
			// Analizati ce s-ar intampla daca lantul pipe-and-filter ar fi
			// circular.
			while ( inputFileSync.ready() ||
					filterSplitIACD.busy() || 
					
					IACDSync.ready() || 
					iacd13456.busy()||
					IACD_No13456_Sync.ready() ||
					iacd12333.busy() ||
					IACD_13456_Sync.ready() ||
					IACD_12333_Sync.ready() ||
					mergeIacd.busy() ||
					
					NonIACDSync.ready() ||
					nonIacd13456.busy() ||
					NonIACD_No13456_Sync.ready() ||
					nonIacd12333.busy() ||
					NonIACD_13456_Sync.ready() ||
					NonIACD_12333_Sync.ready() ||
					mergeNonIacd.busy() ||
					NonIACD_merge_Sync.ready() || 
					nonIacd13222.busy() ||
					
					IACD_merge_Sync.ready() ||
					NonIACD_13222_Sync.ready() ||
					
					merge.busy()
					
					) {
				// Afiseaza un semnal de feedback signal si transfera controlul
				// pentru planifcarea altui fir de executie.
				System.out.print('.');
				Thread.yield();
			}

			// _____________________________________________________________________
			// Curatarea sistemului
			// _____________________________________________________________________

			// Distrugerea tuturor filtrelor.
			System.out
					.println("Controller: Distrugerea tuturor componentelor ...");
			filterSplitIACD.interrupt();
			iacd13456.interrupt();
			iacd12333.interrupt();
			mergeIacd.interrupt();
			nonIacd13456.interrupt();
			nonIacd12333.interrupt();
			mergeNonIacd.interrupt();
			nonIacd13222.interrupt();
			merge.interrupt();
			
			// Verificarea faptului ca filtrele sunt distruse.
			while (filterSplitIACD.isAlive() == false
					|| iacd13456.isAlive() == false
					|| iacd12333.isAlive() == false
					|| mergeIacd.isAlive() == false
					|| nonIacd13456.isAlive() == false
					|| nonIacd12333.isAlive() == false
					|| mergeNonIacd.isAlive() == false
					|| nonIacd13222.isAlive() == false
					|| merge.isAlive() == false
					
			) {
				// Afiseaza un semnal de feedback si transfera controlul
				// planificatorului de fire de execuitie.
				System.out.print('.');
				Thread.yield();
			}

			// Distrugerea tuturor conductelor.
			System.out
					.println("Controller: Distrugerea tuturor conectorilor ...");
			inputFileSync.close();
			outputFileSource.close();
			
			IACDSync.close();
			IACDSource.close();
			
			IACD_No13456_Sync.close();
			IACD_No13456_Source.close();
			
			IACD_13456_Sync.close();
			IACD_13456_Source.close();
			
			IACD_12333_Sync.close();
			IACD_12333_Source.close();
			
			NonIACDSync.close();
			NonIACDSource.close();
			
			NonIACD_No13456_Sync.close();
			NonIACD_No13456_Source.close();
			
			NonIACD_13456_Sync.close();
			NonIACD_13456_Source.close();
			
			NonIACD_12333_Sync.close();
			NonIACD_12333_Source.close();
			
			NonIACD_merge_Sync.close();
			NonIACD_merge_Source.close();
			
			IACD_merge_Sync.close();
			IACD_merge_Source.close();
			
			NonIACD_13222_Sync.close();
			NonIACD_13222_Source.close();
			
		} catch (Exception e) {
			// Afisarea de informatii pentru debugging.
			System.out.println("Exceptie aparuta in SystemMain.");
			e.printStackTrace();
			System.exit(1);
		}

		// Final!
		System.out.println("Controller: Final!");
	}
}
